// 并不是给用户程序使用的互斥量
// 是内核原始的互斥量
// 给用户程序使用的还需要增加支持库 libRtt

// 需要解决优先级反转的问题

use alloc::collections::LinkedList;
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};

use rtt_kernel_mutex::KMutex;

use crate::alloc::boxed::Box;
use crate::global::{CURRENT_THREAD, MAX_PRIORITY, SCHEDULE_LIST};
use crate::thread::{ObjThread, _get_boxed_thread_id, rt_thread_update_pri, rt_thread_weak};

struct RawMutex {
    flag: bool,
    using_thread_pri_id: (isize, isize),
    threads: [LinkedList<Box<ObjThread>>; MAX_PRIORITY],
}

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

pub struct Mutex {
    raw: KMutex<RawMutex>,
}

impl Mutex {
    pub const fn new() -> Mutex {
        const L: LinkedList<Box<ObjThread>> = LinkedList::new();
        Mutex {
            raw: KMutex::new(RawMutex {
                flag: true,
                using_thread_pri_id: (-1, -1),
                threads: [L; MAX_PRIORITY],
            }),
        }
    }

    fn not_empty_list(&self) -> Option<usize> {
        let list = self.raw.lock();
        for i in 0..MAX_PRIORITY {
            if !list.threads[i].is_empty() {
                return Some(i);
            }
        }
        None
    }

    pub fn release(&self) {
        let mut raw = self.raw.lock();
        if raw.flag == false {
            // 资源释放
            raw.flag = true;
            raw.using_thread_pri_id = (-1, -1);
            match self.not_empty_list() {
                None => {}
                Some(i) => {
                    // 有等待链表，可能会有优先级继承
                    // 重置掉可能被改变的优先级
                    let mut self_th = CURRENT_THREAD.lock();
                    let mut th = self_th.thread_take_thread();
                    th.restore_priority();
                    // 唤醒线程去使用信号量
                    let th = raw.threads[i].pop_front().unwrap();
                    rt_thread_weak(th);
                }
            }
        }
    }

    pub fn take(&self) {
        loop {
            let mut raw = self.raw.lock();
            let mut cur_th = CURRENT_THREAD.lock();
            let mut list = SCHEDULE_LIST.lock();
            // 获得当前线程的优先级别
            let self_pri = cur_th.thread_get_thread().get_priority();

            if raw.flag == true {
                // 占用资源
                raw.flag = false;
                // 将自己的优先级别和ID号写入
                raw.using_thread_pri_id = (
                    self_pri as isize,
                    _get_boxed_thread_id(cur_th.thread_get_thread()) as isize,
                );
                return;
            } else {
                // 不能取得资源
                // 推入等待表中
                raw.threads[self_pri].push_back(cur_th.get_thread_set_sp().unwrap());
                if raw.using_thread_pri_id.0 > self_pri as isize {
                    // 使用互斥量的线程优先级低
                    // 手动升高它的优先级别
                    // 根据互斥量中记录的ID号寻找到其线程
                    let uid = raw.using_thread_pri_id.1;
                    if uid == -1 {
                        panic!()
                    }
                    rt_thread_update_pri(
                        (
                            raw.using_thread_pri_id.1 as usize,
                            raw.using_thread_pri_id.0 as usize,
                        ),
                        self_pri,
                    );
                }
                // 挂起当前的线程
                let th = cur_th.get_thread_set_sp().unwrap();
                list[th.get_priority()].push_back(th);
            }
        }
    }
}

// 供MLib使用的API
unsafe impl<T: ?Sized + Send> Send for MLibMutex<T> {}
unsafe impl<T: ?Sized + Send> Sync for MLibMutex<T> {}

pub struct MLibMutex<T: ?Sized> {
    mutex: Mutex,
    data: UnsafeCell<T>,
}

impl<T> MLibMutex<T> {
    pub fn new(t: T) -> Self {
        MLibMutex {
            mutex: Mutex::new(),
            data: UnsafeCell::new(t),
        }
    }

    pub fn lock(&self) -> MLibMutexGuard<T> {
        self.mutex.take();
        MLibMutexGuard {
            __mutex: &self.mutex,
            __data: &self.data,
        }
    }
}

pub struct MLibMutexGuard<'a, T: ?Sized + 'a> {
    __mutex: &'a Mutex,
    __data: &'a UnsafeCell<T>,
}

impl<'mutex, T: ?Sized> Deref for MLibMutexGuard<'mutex, T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.__data.get() }
    }
}

impl<'mutex, T: ?Sized> DerefMut for MLibMutexGuard<'mutex, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.__data.get() }
    }
}

impl<'a, T: ?Sized> Drop for MLibMutexGuard<'a, T> {
    fn drop(&mut self) {
        self.__mutex.release()
    }
}
